/*
 * <Pezad Platformer>
 * Copyright 2008 Shayne Riley
 * 
 * This file is part of <Pezad Platformer>.
 * 
 * <Pezad Platformer> is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * <Pezad Platformer> is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with <Pezad Platformer>.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * To contact the authors on questions or issues regarding the license,
 * you may send an email to <shayner@gmail.com> or write to
 * Shayne Riley / P.O. Box 1092 / McCook, NE 69001.
 */

#ifndef CONTROL_H_
#define CONTROL_H_

#include <iostream>
#include <list>
#include "ControlReceiver.h"
#include "InputHandler.h"

namespace pzdControl
{

/**
 * @brief Control sub-system Translates input from the user into game actions.
 * 
 * Spawns a thread which will listen to various inputs from the user and
 * system, translating these inputs into client-friendly logic.
 */
class Control
{
    public:
    	//! Gives access to the only control instance.
    	static Control& getInstance();

    	/**
    	 * @brief Adds a listener to a list of classes to be called any time
    	 *	the mouse state changes.
    	 * 
    	 * As one of three special input handlers, the input received from the
    	 * mouse in this fashion is suitable for menus and GUIs.
    	 * 
    	 * The classes will be called in the order they were added.
    	 * 
    	 * @param listener	The class which will be called when the mouse
    	 * 	changes.  
    	 */ 
//    	void addMouseListener(MouseListener& listener);

    	/**
    	 * @brief Removes the mouse listener from the list.
    	 * 
    	 * If the listener did not exist in the list, then nothing happens.
    	 */
//    	void removeMouseListener(MouseListener& listener);

    	/**
    	 * @brief Adds a listener to a list of classes to be called any time
    	 *	the keyboard state changes.
    	 * 
    	 * As one of three special input handlers, the input received from the
    	 * keyboard in this fashion is suitable for menus and GUIs, or when the
    	 * user wants to type text.
    	 * 
    	 * The classes will be called in the order they were added.
    	 * 
    	 * @param listener	The class which will be called when the keyboard
    	 * 	state changes.  
    	 */ 
//    	void addKeyboardListener(KeyboardListener& listener);

    	/**
    	 * @brief Removes the keyboard listener from the list.
    	 * 
    	 * If the listener did not exist in the list, then nothing happens.
    	 */
//    	void removeKeyboardListener(KeyboardListener& listener);

    	/**
    	 * @brief Adds a listener to a list of classes to be called any time
    	 *	the system sends a message to the program.
    	 * 
    	 * This is the only way to get messages from the system, as the general
    	 * input listening system will not cover these calls.
    	 * 
    	 * The classes will be called in the order they were added.
    	 * 
    	 * @param listener	The class which will be called when the system
    	 * 	passes a message.
    	 */ 
//    	void addSystemListener(SystemListener& listener);

    	/**
    	 * @brief Removes the system listener from the list.
    	 * 
    	 * If the listener did not exist in the list, then nothing happens.
    	 */
//    	void removeSystemListener(SystemListener& listener);

    	/**
    	 * @brief Adds a listener to a list of classes to be called any time
    	 *	input is recieved from the user.
    	 * 
    	 * Input from the user includes any button or axis input. 
    	 * 
    	 * The classes will be called in the order they were added.
    	 * 
    	 * @param listener	The class which will be called when the user 
    	 */ 
    	void addInputHandler(InputHandler& handler);

    	/**
    	 * @brief Removes the input listener from the list.
    	 * 
    	 * If the listener did not exist in the list, then nothing happens.
    	 */
    	void removeInputHandler(InputHandler& handler);

    private:
    	//! Constructor for the control sub-system.
    	/**
    	 * There should only be one control-subsystem. Making the constructor
    	 * private ensures this happens.
    	 */
        Control();

        //! Destructor for a class that will never be derived from.
        ~Control();

        //! Does all the initialization for the class.
        void init();

        //! Does all the cleaning up and such for the class.
        void finalize();

        //! No copying needed, do not allow. Copy ctor declared, not defined.
        Control(const Control& rhs);        
        //! No assignment needed. Do not define this function.
        Control& operator=(const Control rhs);
        //! No address-of needed. Do not define this function.
        Control* operator&();
        //! No const address-of needed. Do not define this function.
        const Control* operator&() const;

        //! SDL is C-based. We need a static funtion to start the thread.
        static int controlThreadEntryPoint(void *data);

        class InputListener
        {
        public:
        	InputListener(InputHandler &handler)
        	: mHandler(handler)
        	{}

        	InputHandler& getHandler()
        	{
        		return mHandler;
        	}
        private:
        	InputHandler &mHandler;
        	
        };

        //! Holds all the listeners to call when input is received from user.
        std::list<InputListener> inputList;

};

} // namespace

#endif /*CONTROL_H_*/
